#!/usr/bin/env python

"""
A cvmfs_broker plugin that provides users a simple shell interface to query
for system status.
"""

import sys
import inspect
import threading
import pickle
import cvmfs_plugin

class TellmeMessage:

    def __init__(self, seqno, data):
        self.seqno = seqno
        self.data = data

def argcount(func):
    if callable(func):
        spec = inspect.getargspec(func)
        return len(spec.args)
    return 0

class Tellme(cvmfs_plugin.Plugin):

    def __init__(self, target):
        cvmfs_plugin.Plugin.__init__(self, target)
        self.subscribe('TELLME')
        self.subscribe('TELLYOU')

        self.seqno = 0
        self.response = ""
        self.reply_lock = threading.Lock()
        self.reply_cv = threading.Condition(self.reply_lock)
        
    def handle_msg(self, src, subject, body):
        if subject == 'TELLME':
            req = pickle.loads(body)
            lines = req.data.splitlines()
            cmd = lines[0]
            args = lines[1:]
            results = ''
            # there may be security problems here
            if cmd in Tellme.__dict__:
                func = Tellme.__dict__[cmd]
                if callable(func) and argcount(func) == len(args) + 1: 
                    results = func(self, *args)
                else:
                    results = "Wrong command usage"
            else:
                results = "I'm sorry, but I cannot handle command %s" % cmd
            rep = TellmeMessage(req.seqno, results)
            self.unicast(src, 'TELLYOU', pickle.dumps(rep))
        elif subject == 'TELLYOU':
            # response
            rep = pickle.loads(body)
            self.reply_cv.acquire()
            if rep.seqno == self.seqno:
                # this is the response we are waiting for
                self.response = rep.data
                self.reply_cv.notify()
            self.reply_cv.release()

    def execute(self, cmd, *args):
        if cmd in ('help', 'h'):
            self._help()
        elif cmd in ('ls', 'list'):
            print '\n'.join(self.list_peers())
        else:
            if cmd in Tellme.__dict__:
                if argcount(Tellme.__dict__[cmd]) == len(args):
                    self.reply_cv.acquire()
                    req = TellmeMessage(self.seqno, '\n'.join((cmd,)+args[1:]))
                    self.unicast(args[0], "TELLME", pickle.dumps(req))
                    self.reply_cv.wait(5)
                    if not self.response:
                        print "Execution of command %s timed out" % cmd
                    else:
                        print self.response
                        self.response = ""
                    self.seqno += 1
                    self.reply_cv.release()
                else:
                    print 'Incompatible arguments for command %s' % cmd
            else:
                print "Command %s not found" % cmd

    ################################
    ### remote function handlers ###
    ################################

    def info(self):
        return 'Hello'

    def _help(self):
        print 'help:         print this message'
        print 'list:         list participanting peers'
        print 'info <peer>:  show the informatino of a specified peer'
        print 'quit:         quit'


if __name__ == '__main__':
    if len(sys.argv) < 2:
        print 'Usage: %s <target_pid>' % sys.argv[0]
        sys.exit(1)
    tellme = Tellme(int(sys.argv[1]))
    while True:
        cmd = raw_input('> ')
        if cmd in ('quit', 'q', 'exit'):
            tellme.close()
            break
        ca = cmd.split()
        tellme.execute(ca[0], *ca[1:])

    print 'Bye!'

